#include "mainwindow.h"
#include <QApplication>
#include <Windows.h>
#include "RecordManager.h"
#include "benchmark_util.h"
#include "API.h"
#include "CatalogManager.h"
#include "IndexManager.h"
#include "JudgeCondition.h"
#include <conio.h>

void pauseProgram()
{
    cout << "Press any key to continue..." << endl;
    getchar();
}

int main(int argc, char *argv[])
{
    /*QApplication a(argc, argv);
    MainWindow w;
    w.resize(640,480);
    w.setWindowTitle("MiniSQL");
    w.show();

    return a.exec();*/


    /****************** Test for lab1 ********************/
//    RecordManager rm;
    API api;
    CatalogManager cm;
    RecordManager rm;

    api.Record_Manager_Pointer = &rm;
    api.Catalog_Manager_Pointer = &cm;
    IndexManager im(&api);

    api.Index_Manager_Pointer = &im;
    rm.api = &api;

    vector<vector<string>> nationRecords;
    vector<Nation> nations;
    parse_nation_file(nations, nationRecords, "benchmark_data/nation.tbl");

    cout << "[IndexMgr Test]: " << "Read data from nation.tbl" << endl;
    vector<Attribute> nation_attrs;

    nation_attrs.push_back(Attribute("nationKey", 0, true));
    nation_attrs.push_back(Attribute("name", 25, true));
    nation_attrs.push_back(Attribute("regionKey", 0, false));
    nation_attrs.push_back(Attribute("comments", 152, false));

    cout << "[IndexMgr Test]: " << "Set attribute table success!" << endl;
    api.tableCreate("Nation", &nation_attrs, "nationKey", 0);

    int testSetSize = 25;
    for (int i = 0; i < testSetSize; i++)
    {
        api.recordInsert("Nation", &nationRecords[i]);
    }

    vector<vector<string>> customerRecords;
    vector<Customer> custs;
    parse_customer_file(custs, customerRecords, "benchmark_data/customer.tbl");

    cout << "[IndexMgr Test]: " << "Read data from customer.tbl" << endl;
    vector<Attribute> customer_attrs;

    customer_attrs.push_back(Attribute("custKey", 0, true));
    customer_attrs.push_back(Attribute("name", 25, true));
    customer_attrs.push_back(Attribute("address", 40, false));
    customer_attrs.push_back(Attribute("nationKey", 0, false));
    customer_attrs.push_back(Attribute("phone", 15, false));
    customer_attrs.push_back(Attribute("acctbal", -1, false));
    customer_attrs.push_back(Attribute("mktSegment", 10, false));
    customer_attrs.push_back(Attribute("comments", 117, false));

    cout << "[IndexMgr Test]: " << "Set attribute table success!" << endl;
    api.tableCreate("Customer", &customer_attrs, "custKey", 0);

    testSetSize = 100;
    for (int i = 0; i < testSetSize; i++)
    {
        api.recordInsert("Customer", &customerRecords[i]);
    }

    vector<vector<string>> regionRecords;
    vector<Region> regions;
    parse_region_file(regions, regionRecords, "benchmark_data/region.tbl");

    cout << "[IndexMgr Test]: " << "Read data from region.tbl" << endl;
    vector<Attribute> region_attrs;

    region_attrs.push_back(Attribute("regionKey", 0, true));
    region_attrs.push_back(Attribute("name", 25, true));
    region_attrs.push_back(Attribute("comments", 152, false));

    cout << "[IndexMgr Test]: " << "Set attribute table success!" << endl;
    api.tableCreate("Region", &region_attrs, "regionKey", 0);

    testSetSize = 5;
    for (int i = 0; i < testSetSize; i++)
    {
        api.recordInsert("Region", &regionRecords[i]);
    }

//    api.recordShow("Customer");
    vector<Condition> conds;
    string testCustName1 = "Customer#000000019";
    string testCustName2 = "Customer#000000002";
    cout << "Start Test..." << endl;
    pauseProgram();
    cout << "****************Select Test(No index)****************" << endl;
//    getchar();
//    cout << "Press any key to continue..." << endl;
    cout << "================Equal Value Select(No index)================" << endl;
    cout << "[Test 1]: SELECT * FROM Customer WHERE name = Customer#000000019" << endl;

    pauseProgram();

    conds.push_back(Condition("name", "Customer#000000019", 0));
    api.recordShow("Customer", NULL, &conds);

    cout << "================Not Equal Value Select(No index)================" << endl;
    cout << "[Test 2]: SELECT * FROM Customer WHERE name != Customer#000000019" << endl;

    pauseProgram();

    conds.pop_back();
    conds.push_back(Condition("name", "Customer#000000019", 1));
    api.recordShow("Customer", NULL, &conds);

    cout << "================Range Select(No index)================" << endl;
    cout << "[Test 3]: SELECT * FROM Customer WHERE name > Customer#000000002 AND name < Customer#000000019" << endl;

    pauseProgram();

    conds.pop_back();
    conds.push_back(Condition("name", "Customer#000000002", 3));
    conds.push_back(Condition("name", "Customer#000000019", 2));
    api.recordShow("Customer", NULL, &conds);

    cout << "================Multi-conditions Select(No index)================" << endl;
    cout << "[Test 4]: SELECT * FROM Customer WHERE name > Customer#000000002 AND name < Customer#000000019 AND nationKey=2" << endl;

    pauseProgram();

    conds.pop_back();
    conds.pop_back();
    conds.push_back(Condition("name", "Customer#000000002", 3));
    conds.push_back(Condition("name", "Customer#000000019", 2));
    conds.push_back(Condition("nationKey", "2", 0));
    api.recordShow("Customer", NULL, &conds);
    // clear condition

    cout << "****************Select Test(Use index)****************" << endl;

    conds.pop_back();
    conds.pop_back();
    conds.pop_back();
    cout << "Creating index: " << "custName_index" << "..." << endl;
    string index1 = "custName_index";
    api.indexCreate(index1, "Customer", "name");
    cout << "================Equal Value Select(Use index)================" << endl;
    cout << "[Test 1]: SELECT * FROM Customer WHERE name = Customer#0000000019" << endl;
    pauseProgram();
    conds.push_back(Condition("name", "Customer#000000019", 0));
    api.recordShow("Customer", NULL, &conds);


    cout << "================Not Equal Value Select(Use index)================" << endl;
    cout << "[Test 2]: SELECT * FROM Customer WHERE name != Customer#0000000019" << endl;
    pauseProgram();
    conds.pop_back();
    conds.push_back(Condition("name", "Customer#000000019", 1));
    api.recordShow("Customer", NULL, &conds);

    cout << "================Range Select(Use index)================" << endl;
    cout << "[Test 3]: SELECT * FROM Customer WHERE name > Customer#000000002 AND name < Customer#000000019" << endl;
    pauseProgram();
    conds.pop_back();
    conds.push_back(Condition("name", "Customer#000000002", 3));
    conds.push_back(Condition("name", "Customer#000000019", 2));
    api.recordShow("Customer", NULL, &conds);

    cout << "================Multi-conditions Select(Use index)================" << endl;
    cout << "[Test 4]: SELECT * FROM Customer WHERE name > Customer#000000002 AND name < Customer#000000019 AND nationKey=2" << endl;
    pauseProgram();
    conds.pop_back();
    conds.pop_back();
    conds.push_back(Condition("name", "Customer#000000002", 3));
    conds.push_back(Condition("name", "Customer#000000019", 2));
    conds.push_back(Condition("nationKey", "2", 0));
    api.recordShow("Customer", NULL, &conds);

    cout << "****************Projection Test****************" << endl;
    conds.pop_back();
    conds.pop_back();
    conds.pop_back();
    vector<string> attribs;
    attribs.push_back("custKey");
    attribs.push_back("address");
    attribs.push_back("acctbal");

    cout << "================Multi-columns Project================" << endl;
    cout << "[Test 1]: SELECT custKey, address, acctbal FROM Customer" << endl;
    pauseProgram();
    api.recordShow("Customer", &attribs, &conds);

    cout << "================All-columns Project================" << endl;
    cout << "[Test 2]: SELECT * FROM Customer" << endl;
    pauseProgram();
    api.recordShow("Customer", NULL, &conds);


    cout << "****************Join Test****************" << endl;
    cout << "================Two Tables Cartesian Join================" << endl;
    cout << "[Test 0]: Cartesian for table Region and table Nation" << endl;
    pauseProgram();
    api.recordCartesianJoinAndShow("Region", "Nation");

    cout << "================Two Tables Equal Value Join================" << endl;
    cout << "[Test 1]: SELECT nation.nation_key, nation.name, region.name, region.region_key FROM nation, region WHERE nation.region_key = region.region_key" << endl;
    pauseProgram();
    api.recordJoin("Nation", "Region", nations, regions);

    cout << "================Three Tables Equal Value Join================" << endl;
    cout << "[Test 2]: SELECT customer.name, nation.nation_key, nation.name, region.name, region.region_key FROM nation, region, customer WHERE nation.region_key = region.region_key AND customer.nation_key = nation.nation_key" << endl;
    pauseProgram();
    api.recordJoin("Nation", "Region", "Customer", nations, regions, custs);

    cout << "================Two Tables Not Equal Value Join================" << endl;
    cout << "[Test 3]: SELECT nation.nation_key, nation.name, region.name, region.region_key FROM nation, region WHERE nation.region_key != region.region_key" << endl;
    pauseProgram();
    api.recordNotEqualJoin("Nation", "Region", nations, regions);

    cout << "================Two Tables Hash Join================" << endl;
    cout << "[Test 4]: SELECT nation.nation_key, nation.name, nation.region_key, region.name, region.region_key FROM nation, region WHERE nation.region_key = region.region_key" << endl;
    pauseProgram();
    api.recordHashJoin("Nation", "Region", nations, regions);

    cout << "================Two Tables Merge-sort Join================" << endl;
    cout << "[Test 5]: SELECT nation.nation_key, nation.name, nation.region_key, region.name, region.region_key FROM nation, region WHERE nation.region_key = region.region_key" << endl;
    pauseProgram();
    api.recordMergeSortJoin("Nation", "Region", nations, regions);

    return 0;
}
